package hyl.base.net.bio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;

import hyl.base.net.IData1;
import hyl.base.net.IpgReader;
import hyl.base.net.ISocketCli;
import hyl.core.MyFun;
import hyl.core.run.IDo1;
import hyl.core.run.MyRun;

//一个客户端只能连接一个服务端
//如果要连接多个需要客户端管理
public class BIOSocketCli extends BIOSocket implements ISocketCli {

	Socket _client;
	InetSocketAddress remoteAddress;

	public Socket getClientSocket() {
		return _client;
	}

	/**
	 * 实例化服务端<br>
	 * 这是专门为了 小集群系统(小于256个微服务程序) 设计的 微服务底层通信组件<br>
	 * 特别注意这不是nio 模式,每个线程针对一个客户端,保持长连接<br>
	 * , 超过128线程 ,将无法接入客户端<br>
	 * 如果需要大量的客户端绑定,我们设计了NIOsocket 组件 <br>
	 * 
	 * 大量的对象 需要非常大的内存,如何优化是关键
	 * 
	 * 构造函数，必须输入端口号
	 * 
	 * @param port   服务端口
	 * @param 接收处理函数 一个socket 一个处理函数与线程对应
	 * 
	 * 
	 * 
	 */
	public BIOSocketCli(InetSocketAddress 连接地址, IDo1<IpgReader> 收到处理函数) {
		this(连接地址);
		_IDo接收处理函数 = 收到处理函数;
	}

	public BIOSocketCli(InetSocketAddress 连接地址) {
		_work = MyRun.getInstance("bio-cli"+连接地址.getHostString());
		remoteAddress = 连接地址;
		ini();
	}

//实例化客户端
	public BIOSocketCli(String 服务端ip, int port) {
		this(new InetSocketAddress(服务端ip, port));
	}

	public BIOSocketCli(String 服务端ip, int port, IDo1<IpgReader> 收到处理函数) {
		this(服务端ip, port);
		_IDo接收处理函数 = 收到处理函数;

	}

//初始化 只执行一次
	protected void ini() {
		if (_client == null) {
			String stt = MyFun.join("接入服务端:", remoteAddress);
			try {
				_client = new Socket(remoteAddress.getAddress(), remoteAddress.getPort());
				_log.info(stt);
			} catch (IOException e) {
				_log.error(MyFun.join("无法", stt), e.getMessage());
			}
		}

	}

	BIOReader read = null;

	public IpgReader startReader() {
		if (read == null && _IDo接收处理函数 != null) {
			read = new BIOReader(_client, _IDo接收处理函数);
			_work.execute(read);
		}
		return read;
	}

	/**
	 * 连续接收反馈数据
	 * 
	 * @param 回调
	 */
	public void getResult(IDo1<byte[]> 回调) {
		IpgReader rd = startReader();
		rd.pullData(回调);
	}

	/**
	 * 接收一次反馈数据
	 * 
	 * @param 回调
	 */
	public byte[] getResult() {
		IpgReader rd = startReader();
		return rd.pullData();
	}

	@Override
	public void close() {
		_work.close();
		b是否退出程序 = true;
		try {
			_client.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 发送后不管
	 */
	public boolean send(byte[] 数据包){
		return send(_client, IData1.B类型_数据, 数据包);
	}

	/**
	 * 发送后不管
	 */
	public boolean send(byte 类型, byte[] 数据包) {
		return send(_client, 类型, 数据包);
	}

	/**
	 * 发一次等待一次接收,效率慢一点但是逻辑清楚.
	 * 
	 * 多次发送一次接收,或者一次发送多次接收都属于特例 需要直接写.
	 * 
	 * 只要把send 与 getResult 结合起来就可以了.
	 * 
	 * 发送后不关闭连接,加快处理速度
	 * 
	 * @param 数据包
	 * @return
	 * @throws IOException 
	 */
	public byte[] request(byte[] 数据包) throws IOException {
		send(_client, IData1.B类型_数据, 数据包);
		IpgReader rd = startReader();
		return rd.pullData();
	}
	public byte[] request(byte 类型, byte[] 数据包) throws IOException {
		send(_client, 类型, 数据包);
		IpgReader rd = startReader();
		return rd.pullData();
	}
}
